// i.d(t, { S: () => c, Z: () => PanoQualityManager })

import PersistentStorage from "../storage/PersistentStorage"
import o from "../math/14844"
import OpenDeferred from "./OpenDeferred"
import Logger from "./Logger"
import resolutionEnum, { resolutionKey, resolutionVal } from "../enum/resolution.enum"
import configConst from "../constant/config.const"
import ModelDataModule from "../module/ModelDataModule"
import Sweep from "../object/Sweep"
const l = new Logger("panoqualitymanager")

export const TestResults = {
  Untested: 0,
  Testing: 1,
  Success: 2,
  Fail: 3,
  0: "Untested",
  1: "Testing",
  2: "Success",
  3: "Fail"
}

export default class PanoQualityManager {
  urls: ModelDataModule["signedUrls"]
  maxCubemapSize: number
  maxNavPanoSize: number
  maxZoomPanoSize: number
  overrideWindow: boolean
  devicePixelRatio: number
  navPanoSize: number
  zoomPanoSize: number
  windowHeight: number
  highQualityThreshold: any
  persistentStorage: PersistentStorage
  downloadTestResults: Record<string, Record<string, number>>
  constructor(e: ModelDataModule["signedUrls"], t: number, i: number, n: number) {
    this.urls = e
    this.maxCubemapSize = t
    this.maxNavPanoSize = i
    this.maxZoomPanoSize = n
    this.overrideWindow = !1
    this.devicePixelRatio = window.devicePixelRatio || 1
    this.navPanoSize = -1
    this.zoomPanoSize = -1
    this.windowHeight = window.innerHeight * this.devicePixelRatio
    this.highQualityThreshold = configConst.tileConfig.windowHeightHighQualityThresholdOverride || configConst.tileConfig.windowHeightHighQualityThreshold
    this.persistentStorage = new PersistentStorage()
    this.downloadTestResults = {}
    this.updateMaximums()
  }
  setWindowSize(e, t) {
    this.windowHeight = t * this.devicePixelRatio
    this.updateMaximums()
  }
  overrideWindowMaximums(e) {
    this.overrideWindow = e
    this.updateMaximums()
  }
  updateNavPanoSize(e) {
    this.maxNavPanoSize = e
    this.updateMaximums()
  }
  getTestResults(e, t) {
    const i = this.downloadTestResults[e]
    if (i) {
      const e = i[t]
      if (e) return e
    }
    return TestResults.Untested
  }
  ultraHighQualityModeEnabled(e) {
    const t = resolutionKey[this.getZoomPanoSize()]
    const i = this.downloadTestResults[e]
    return !(!i || !i[t]) && i[t] === TestResults.Success
  }
  updateMaximums() {
    this.windowHeight < this.highQualityThreshold && !this.overrideWindow
      ? ((this.navPanoSize = Math.min(PanoQualityManager.getPanoSize(resolutionEnum.STANDARD), this.maxNavPanoSize)),
        (this.zoomPanoSize = Math.min(PanoQualityManager.getPanoSize(resolutionEnum.HIGH), this.maxZoomPanoSize)))
      : ((this.navPanoSize = this.maxNavPanoSize), (this.zoomPanoSize = this.maxZoomPanoSize)),
      this.zoomPanoSize < this.navPanoSize && (this.navPanoSize = this.zoomPanoSize),
      (this.zoomPanoSize = Math.min(this.maxCubemapSize, this.zoomPanoSize)),
      (this.navPanoSize = Math.min(this.maxCubemapSize, this.navPanoSize))
  }
  static getPanoSize(e): number {
    if (e in resolutionVal) return resolutionVal[e]
    throw new Error(`Not a panoSizeClass: ${e}`)
  }
  static getPanoSizeClass(e): string {
    if (e in resolutionKey) return resolutionKey[e]
    throw new Error(`Not a valid pano resolution: ${e}`)
  }
  getMaxPossiblePanoSize() {
    return PanoQualityManager.getPanoSize(resolutionEnum.ULTRAHIGH)
  }
  getNavPanoSize() {
    return this.navPanoSize
  }
  getZoomPanoSize() {
    return this.zoomPanoSize
  }
  availableResolution(e, t?: string): OpenDeferred {
    const i = new OpenDeferred()
    if (!t) return i.reject(0)
    if (e.resolutions) return e.resolutions.includes(t) ? i.resolve(t) : this.availableResolution(e, this.getLowerResolution(t))
    switch (this.getTestResults(e.id, t)) {
      case TestResults.Success:
        i.resolve(t)
        break
      case TestResults.Fail:
        return this.availableResolution(e, this.getLowerResolution(t))
      case TestResults.Untested:
        this.testDownload(e, t, o.I_).then(n => {
          n ? i.resolve(t) : this.availableResolution(e, this.getLowerResolution(t)).then(e => i.resolve(e))
        })
        break
      case TestResults.Testing:
        l.warn("resolution is already testing, do we need to handle this?")
    }
    return i
  }
  getLowerResolution(e: string) {
    switch (e) {
      case resolutionEnum.ULTRAHIGH:
        return resolutionEnum.HIGH
      case resolutionEnum.HIGH:
        return resolutionEnum.STANDARD
      case resolutionEnum.STANDARD:
        return resolutionEnum.BASE
    }
    return undefined
  }
  testDownload(e: Sweep, t: string, i: number) {
    if (!this.urls) throw new Error("Can't call testDownload without signed urls")
    const n = PanoQualityManager.getPanoSize(t)
    const s = new OpenDeferred<boolean>()
    const r = e.id
    this.downloadTestResults[r] || (this.downloadTestResults[r] = {})
    const o = this.downloadTestResults[r] && this.downloadTestResults[r][t]
    if (o) o === TestResults.Success ? s.resolve(!0) : o === TestResults.Fail && s.resolve(!1)
    else {
      this.downloadTestResults[r][t] = TestResults.Testing
      const resolve = e => {
        this.downloadTestResults[r][t] = TestResults.Success
        s.resolve(!0)
      }
      const reject = () => {
        this.downloadTestResults[r][t] = TestResults.Fail
        s.resolve(!1)
      }
      this.getTileUrl(e, n, i, 0).then(e => {
        this.urls.getImage(e).then(resolve, reject)
      })
    }
    return s
  }
  getTileUrl(e: Sweep, t: number, i: number, n: number) {
    const s = this.persistentStorage.get("getTileUrl:locationInfo", () => ({
      face: -1,
      faceTileIndex: -1,
      tileX: -1,
      tileY: -1
    }))
    o.Tp(t, n, s)
    const r = Math.floor(t / i),
      a = r * r,
      l = Math.floor(n / a),
      c = PanoQualityManager.getPanoSizeClass(t)
    return e.getTileUrl(c, l, s.tileX, s.tileY)
  }
}
// export default { S: c, Z: PanoQualityManager }
